/*
	This file is part of PropExtractor.

	PropExtractor is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	PropExtractor is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with PropExtractor. If not, see <http://www.gnu.org/licenses/>.
*/

#include "PEIncludes.h"

#include "PEAliceSoftArchiveRed.h"

#include "PETools.h"
#include "PEArchive.h"

#include "PEAliceSoftImageQNT.h"
#include "PEAliceSoftModel.h"

namespace pe
{

	// ================================
	// Zip
	// ================================

	int AliceArchiveRedReadHeader(AliceArchiveRedHeader* a_Target, PEStream* a_Stream)
	{
		PEStreamRead(a_Stream, a_Target, sizeof(AliceArchiveRedHeader), 1);

		PE_DEBUG("Header: %s", a_Target->header);

		if (
			a_Target->header[0] != 'A' ||
			a_Target->header[1] != 'A' ||
			a_Target->header[2] != 'R'
		)
		{
			return -1;
		}

		return PE_OK;
	}

	int AliceArchiveRedReadData(AliceArchiveRed* a_Target, AliceArchiveRedHeader* a_Header, PEStream* a_Stream)
	{
		a_Target->header = a_Header;

		a_Target->handle = new PEStream;
		PEStreamCopy(a_Target->handle, a_Stream);

		PEStreamGetDir(a_Stream, &a_Target->workingdir);

		a_Target->files_total = a_Header->number_of_files;
		a_Target->files = new AliceArchiveRedFile[a_Target->files_total];

		char temp[256];
		AliceArchiveRedFile* dst = a_Target->files;
		for (unsigned int i = 0; i < a_Target->files_total; i++)
		{
			dst->header = new AliceArchiveRedFileHeader;
			PEStreamRead(a_Stream, dst->header, sizeof(AliceArchiveRedFileHeader), 1);

			memset(temp, 0, 256);
			int j = 0;
			do 
			{
				PEStreamRead(a_Stream, &temp[j], 1, 1);
			} 
			while (temp[j++] != 0 && j < 256);

			PE_STRCLRCPY(dst->path, temp);

			dst++;
		}

		return PE_OK;
	}

	int AliceArchiveRedOpenFile(PEStream* a_Target, AliceArchiveRed* a_Zip, unsigned int a_Index)
	{
		/*// open another handle to the zip...

		PEStreamOpen(a_Target, a_Zip->handle->path, L"rb", false);
		PEStreamSetPath(a_Target, a_Zip->files[a_Index].path);

		// ... but with an offset

		PEStreamSeek(a_Target, a_Zip->files[a_Index].header->offset, SEEK_SET);*/

		return PE_OK;
	}

	int AliceArchiveRedExtractFile(AliceArchiveRed* a_Zip, unsigned int a_Index, const char* a_Pattern)
	{
		/*char filepath[_MAX_PATH];
		strcpy(filepath, a_Zip->workingdir);
		strcat(filepath, a_Zip->files[a_Index].path);
		
		if (CheckDirectory(filepath) != PE_OK) { return -1; }

		FILE* handle = fopen(filepath, "w+b");
		if (!handle) { return -1; }

		PEStreamSeek(a_Zip->handle, a_Zip->files[a_Index].header->offset, SEEK_SET);

		size_t filesize;
		if (a_Index == a_Zip->files_total - 1)
		{
			unsigned int pos_curr;
			unsigned int totalsize;
			PEStreamGetCurrentPos(a_Zip->handle, &pos_curr);
			PEStreamSeek(a_Zip->handle, 0, SEEK_END);
			PEStreamGetCurrentPos(a_Zip->handle, &totalsize);
			PEStreamSeek(a_Zip->handle, pos_curr, SEEK_SET);

			filesize = totalsize - a_Zip->files[a_Index].header->offset;
		}
		else
		{
			filesize = a_Zip->files[a_Index + 1].header->offset - a_Zip->files[a_Index].header->offset;
		}

		byte* temp = new byte[filesize];		
		PEStreamRead(a_Zip->handle, temp, 1, filesize);

		fwrite(temp, filesize, 1, handle);

		fclose(handle);

		delete temp;*/

		return PE_OK;
	}

	int AliceArchiveRedSaveImageToFile(AliceArchiveRed* a_ZipFile, unsigned int a_Index, const char* a_Pattern)
	{
		/*PE_DEBUG("SaveImageToFile");

		PEStream read;
		AliceArchiveRedOpenFile(&read, a_ZipFile, a_Index);

		AliceImageQNTHeader header;
		if (AliceImageQNTReadHeader(&header, &read) != 0) { return -1; }

		PE_DEBUG("Saving image to file.");

		AliceImageQNT image;
		AliceImageQNTReadData(&image, &header, &read);

		PEImageRaw raw;
		AliceImageQNTDecrypt(&raw, &image);

		char path[_MAX_PATH];
		size_t path_len;
		if (a_Pattern)
		{
			GetPatternedPath(path, &path_len, a_Pattern, read.path, a_ZipFile->workingdir, a_Index);
		}
		else
		{
			strcpy(path, a_ZipFile->workingdir);
			strcat(path, read.path);
		}

		PE_DEBUG("Path: %s", path);

		PEImageRawSaveToFile(&raw, path);

		PE_DEBUG("Crash?");

		//PE_PRINT("Saved image to '%s'.", path);*/

		return PE_OK;
	}

	int AliceArchiveRedSaveModelToFile(AliceArchiveRed* a_ZipFile, unsigned int a_Index, const char* a_Pattern /*= NULL*/)
	{
		/*PEStream read;
		AliceArchiveRedOpenFile(&read, a_ZipFile, a_Index);

		AliceModelZippedHeader header;
		if (AliceZippedModelReadHeader(&header, &read) != PE_OK) { return -1; }

		AliceModelData data;
		AliceZippedModelDecompress(&data, &header, &read);

		AliceModel model;
		if (AliceModelDecrypt(&model, &data) != PE_OK) { return -1; }

		char path[_MAX_PATH];
		size_t path_len;
		if (a_Pattern)
		{
			GetPatternedPath(path, &path_len, a_Pattern, read.path, a_ZipFile->workingdir, a_Index);
		}
		else
		{
			strcpy(path, a_ZipFile->workingdir);
			strcat(path, read.path);
		}

		AliceModelSaveToObj(&model, path);

		//PE_PRINT("Saved model to '%s'.", path);*/

		return PE_OK;
	}

	PE_EXPORT int AliceArchiveRedToRaw(PEArchiveRaw* a_Target, AliceArchiveRed* a_Archive)
	{
		a_Target->original = new AliceArchiveRed;
		memcpy(a_Target->original, a_Archive, sizeof(AliceArchiveRed));
		a_Target->original_type = eArchiveType_AliceRed;

		PE_WSTRCLRCPY(a_Target->path, a_Archive->handle->path);
		PE_WSTRCLRCPY(a_Target->workingdir, a_Archive->workingdir);

		a_Target->entries_total = a_Archive->files_total;
		a_Target->entries = new PEArchiveEntryRaw[a_Target->entries_total];

		for (unsigned int i = 0; i < a_Target->entries_total; i++)
		{
			PE_STRTOWIDE(a_Target->entries[i].path, a_Archive->files[i].path);

			a_Target->entries[i].offset = a_Archive->files[i].header->offset;
			a_Target->entries[i].filesize = a_Archive->files[i].header->size;

			wchar_t filename[_MAX_PATH];
			unsigned int filename_length;
			GetPatternedPath(filename, &filename_length, "%name%.%ext%", a_Target->entries[i].path);

			PE_WSTRCLRCPY(a_Target->entries[i].filename, filename);
		}

		return PE_OK;
	}

}; // namespace pe